// #include "openssl/include/openssl/rsa.h"
// #include "openssl/bio.h"
// #include "openssl/include/openssl/pem.h"
#include <stdio.h>
// #pragma comment(lib, "test.lib")
#include "openssl/rsa.h"
#include "openssl/pem.h"
#include "openssl/bio.h"
#include "openssl/err.h"
#include "openssl/bn.h"
#include "base64.h"
#include <openssl/applink.c>
// extern C
// {
// #include <openssl/applink.c>
// };

#define PRIVATE_KEY "privateKey.pem"
#define PUBLIC_KEY  "publicKey.pem"

void echo_err()
{
    unsigned long ulErr = ERR_get_error();
    char szErrMsg[1024] = { 0 };
    char *pTmp = NULL;
    pTmp = ERR_error_string(ulErr, szErrMsg);
    printf("bio_read_publicKey %s\n", szErrMsg);
}

void generate_key(void)
{
    RSA* rsa = RSA_new();
    BIGNUM*bne =BN_new();
    BN_set_word(bne, 17);
    if(RSA_generate_key_ex(rsa, 1024, bne, NULL) < 0)
    {
        echo_err();
        return;
    }

    /* 生成公钥 */
	BIO *bp = BIO_new(BIO_s_file());
	BIO_write_filename(bp, PUBLIC_KEY);
	PEM_write_bio_RSAPublicKey(bp, rsa);
	BIO_free_all(bp);
 
	/* 生成私钥 */
	bp = BIO_new(BIO_s_file());
	BIO_write_filename(bp, PRIVATE_KEY);
	PEM_write_bio_RSAPrivateKey(bp, rsa, NULL, NULL, 0, NULL, NULL);
	CRYPTO_cleanup_all_ex_data();
	BIO_free_all(bp);
	RSA_free(rsa);

}

void test_crypto(void)
{
    char *data = "this is used to crypto testing";
 
	OpenSSL_add_all_algorithms();
	BIO* bp = BIO_new(BIO_s_file());
	BIO_read_filename(bp, PUBLIC_KEY);
	RSA* rsaK = PEM_read_bio_RSAPublicKey(bp, NULL, NULL, NULL);
	if (NULL == rsaK) 
	{
		echo_err();
		return ;
	}
 
	int nLen = RSA_size(rsaK);
	char pEncode[nLen + 1];
	int ret = RSA_public_encrypt(strlen(data), data,
								(unsigned char *)pEncode, rsaK, RSA_PKCS1_PADDING);
	if (ret >= 0)
	{
        char bEncode[((nLen + 1)+2)*4/3];
        base64_encode(pEncode, ret, bEncode, &ret);
		printf("crypto success:\n");
        printf("%s\n", bEncode);
	}

	CRYPTO_cleanup_all_ex_data();
	BIO_free_all(bp);
	RSA_free(rsaK);
}

void test_crypto2()
{
    FILE *file;

    /*加密流程： 读取秘钥 -- 公钥加密 -- base64编码*/
    if((file=fopen(PRIVATE_KEY,"r"))==NULL){
        printf("open key file error\n");
        return ;
    }
    RSA *rsa = PEM_read_RSAPrivateKey(file, NULL, NULL, NULL);
    if(rsa == NULL)
    {
        echo_err();
        return;
    }
    //encrypt
    int rsa_len = RSA_size(rsa);
    char *data = "this is test rsa crypt";
    char rsaEncodeData[rsa_len + 1];
    int ret;
    ret = RSA_public_encrypt(strlen(data), data, rsaEncodeData, rsa, RSA_PKCS1_PADDING);
    if(ret < 0)
    {
        echo_err();
        return;
    }
    char base64EncodeData[((rsa_len + 1)+2)*4/3];
    memset(base64EncodeData,0,sizeof(base64EncodeData));
    if(!base64_encode(rsaEncodeData, ret, base64EncodeData, &ret))
    {
        printf("crypto success:\n");
        printf("%s\n", base64EncodeData);
    }
    else printf("base64 encode fail\n");
    printf("rsa_len: %d,ret = %d\n", rsa_len, ret);
    
    RSA_free(rsa);
    fclose(file);

    /*解密密流程： 读取秘钥 -- base64解码 -- 私钥解密*/
    if((file=fopen(PRIVATE_KEY,"r"))==NULL){
        printf("open key file error\n");
        return ;
    }
    if((rsa = PEM_read_RSAPrivateKey(file, NULL,NULL,NULL )) == NULL)
    {
        echo_err();
        return;
    }
    if(base64_decode(base64EncodeData, ret, rsaEncodeData, &ret))
    {
        printf("base64 decode fail\n");
    }
    // decrypt
    char rsaDecodeData[rsa_len + 1];
    if(RSA_private_decrypt(ret, rsaEncodeData, rsaDecodeData, rsa, RSA_PKCS1_PADDING) < 0)
    {
        echo_err();
        return;
    }
    printf("decrypt success:\n");
    printf("%s\n",rsaDecodeData);

    RSA_free(rsa);
    fclose(file);
}

void test_read_key()
{
    RSA *rsa = NULL;
    BIO *bio = NULL;
    int ret;
    char *filename = PRIVATE_KEY;

    //获取私钥
    bio = BIO_new_file(filename, "r");
    if(!bio)
    {
        echo_err();
        return;
    }

    rsa = PEM_read_bio_RSAPrivateKey( bio, &rsa, NULL, NULL );
    if(!rsa)
    {
        echo_err();
        return;
    }

    BIO_free_all(bio);
    RSA_free(rsa);

    //获取公钥
    bio = BIO_new_file(filename, "r");
    if(!bio)
    {
        echo_err();
        return;
    }

    rsa = PEM_read_bio_RSAPublicKey( bio, NULL, NULL, NULL );   //这里会失败，必须读取的是公钥文件
    if(!rsa)
    {
        echo_err();
        return;
    }

    BIO_free_all(bio);
    RSA_free(rsa);
    
}

void generate_key2()
{
    BIO *bio = NULL;
    RSA *rsa = NULL;
    int ret;
    
    rsa = RSA_generate_key(1024, RSA_F4, NULL, NULL);
    if(!rsa)
    {
        echo_err();
        return;
    }

    /*generate public key*/
    bio = BIO_new_file(PUBLIC_KEY, "wb");
    if(!bio)
    {
        echo_err();
        return;
    }

    RSA* RSAPublicKey = RSAPublicKey_dup(rsa);
    ret = PEM_write_bio_RSAPublicKey(bio, RSAPublicKey);
    BIO_free_all(bio);
    RSA_free(RSAPublicKey);

    /*generate private key*/
    bio = BIO_new_file(PRIVATE_KEY, "wb");
    if(!bio)
    {
        echo_err();
        return;
    }

    RSA* RSAPrivateKey = RSAPrivateKey_dup(rsa);
    ret = PEM_write_bio_RSAPrivateKey(bio, RSAPrivateKey, NULL, NULL, 0, NULL, NULL);
    BIO_free_all(bio);
    RSA_free(RSAPrivateKey);

    RSA_free(rsa);
}

void test_read_key2()
{
    BIO *bio = NULL;
    RSA *rsa = NULL;
    int ret,fd;
    char strPublicKey[] = "-----BEGIN RSA PRIVATE KEY-----\
\nMIIBOgIBAAJBAO1avoxTWj0ZB16kkx2tEmwPID38Q0w3Ep3n5WNrv3h0kZAXis8R\
j/WONRk2sOljzPev7bNz0GgqVzWhWz7RGLsCAQMCQQCePH8IN5F+EK+UbbdpHgxI\
ChV+qCzdegxpRUOXnSpQTG2vcBaQlHDWHUurJCBECokOsDWZhXtMOI5ruPhMHEoL\
AiEA+V181QCm02k1S2UhLQfZ6spLi7NUP+J5vvx4GBJ7VKMCIQDzq3KT9YwTSyz4\
M19Te3oUl1wRmddXk1vCl5POuitVCQIhAKY+UzirGeJGI4eYwMiv5pyG3QfM4tVB\
pn9S+rq2/OMXAiEAonJMYqOyt4dzUCI/jPz8Dbo9YRE6OmI9LGUNNHwc41sCIA3l\
XdHvymRjRzXXSlf1IvW7QSEwhYO0ifGXsrTd3t5d\
\n-----END RSA PRIVATE KEY-----\n";

    printf("key: \n%s",strPublicKey);
    // char str[1024];
    // memset(str,0,1024);
    // fd = open(PRIVATE_KEY,O_RDONLY);
    // ret = read(fd,str,1024);
    // printf("key2: \n%s",str);

    bio = BIO_new_mem_buf(strPublicKey, -1);    //如果参数len是－1，那么就默认buf是以null结束
                                                //这时候BIO被设置为只读的，不能执行写操作
    if(!bio)
    {
        echo_err();
        return;
    }               

    // rsa = PEM_read_bio_RSAPublicKey(bio, NULL, NULL, NULL);  //不能用公钥读取方法，因为秘钥为私钥
    rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
    if(!rsa)
    {
        echo_err();
        return;
    }

    printf("rsa size: %d\n",RSA_size(rsa));

    BIO_free_all(bio);
    RSA_free(rsa);
}

void test_decrypt()
{
    char data[] = "BEEmXd8kqZso3wf+oAP1Yr2MEYerPjemFs43NB1I1LdUinMrRjR/E5qbtY8Qa4tCJ68Hlf9qs4XLnuBgEXHX0sFB/VfSR5rRjBOKhlRK1WuiUEkHPfXPz6Na2L4ckGXqZ0RnQOfAk0tH4rMzIzqN7riaRd224OcG4RWi1DWp1gElFsypn15us1mGGjIbz84pN0oXd1PVTzbBMw/SLqHyThmaOny1oNg9NDqwS1usZaSeA8zoT9Df1EpfBJCu+3OaYhQPAtXEAHerijJF6WFGdaesysKNMNQeHbnLvrDno7HncJdNKeY/ZuwLmkc4ERLClNPup/zLaowHqFrtTqEB96O0e9WIBVscJBMClgAHQrOJttPNmPVUFD89VUuNL+wGsaIhLQc38P5R+cRVvsZlU57FN4OE0NEnyYbq9IJyrCrp5RoqC62uo2/XHVdG7tn/2kgpTgn0QugJC8xN0AKMIwBSGirWh7R8IwAY1WNQ/Z0kkZxRzVFpRNbCWJqVy5EG";
    BIO* bio = BIO_new(BIO_s_file());
	BIO_read_filename(bio, PRIVATE_KEY);
	RSA* rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
	if (NULL == rsa) 
	{
		echo_err();
		return ;
	}
    char rEncode[sizeof(data)];
    int rret;
    if(base64_decode(data, strlen(data), rEncode, &rret))
    {
        printf("base64 decode fail\n");
        return;
    }
    char rDecode[rret];
    printf("sizeof(rDecode) = %d\n",sizeof(rDecode));
    int rsa_len = RSA_size(rsa);
    int ret;
    for(int i=0,j=0,k=0; rret; i+=ret,rret-=ret,k+=j)
    {
        ret = rret>rsa_len?rsa_len:rret;
        j = RSA_private_decrypt(ret, rEncode+i, rDecode+k, rsa, RSA_PKCS1_PADDING);
        if(j<0)
        {
            echo_err();
            return ;
        }
    }
    printf("decode:\n%s\n",rDecode);

    BIO_free_all(bio);
    RSA_free(rsa);
}

int main()
{
    // generate_key();
    // test_crypto();
    // test_crypto2();
    // test_read_key();
    // test_read_key2();
    // generate_key2();
    test_decrypt();
    return 0;
}

